////////////////////////////////////////////////////////////////////////////////
//
//  FLEX USER GROUP HOKURIKU
//  Copyright 2009 Flex User Group Hokuriku
//  All Rights Reserved.
// 
//  NOTICE: Flex User Group Hokuriku permits you to use, 
//  modify, and distribute this file 
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package net.fxug.hokuriku.chocolat.helper
{
    import flash.events.Event;
    import flash.events.MouseEvent;

    import mx.controls.Alert;
    import mx.controls.ComboBox;
    import mx.core.IMXMLObject;
    import mx.events.FlexEvent;
    import mx.events.ListEvent;
    import mx.logging.ILogger;

    import net.fxug.hokuriku.chocolat.errors.NetworkInterfaceError;
    import net.fxug.hokuriku.chocolat.events.SocketEvent;
    import net.fxug.hokuriku.chocolat.events.ViewChangeEvent;
    import net.fxug.hokuriku.chocolat.model.NetworkInterfaceData;
    import net.fxug.hokuriku.chocolat.model.NetworkInterfaceManager;
    import net.fxug.hokuriku.chocolat.service.SocketClient;
    import net.fxug.hokuriku.chocolat.service.data.ConnectInfo;
    import net.fxug.hokuriku.chocolat.utils.FilterUtil;
    import net.fxug.hokuriku.chocolat.utils.LoggingUtil;
    import net.fxug.hokuriku.chocolat.view.AudienceSetting;

    /**
     * オーディエンス設定画面のヘルパークラス
     *
     * @author shoito, mac
     */
    public class AudienceSettingHelper implements IMXMLObject
    {
        private static var logger:ILogger = LoggingUtil.getLogger(AudienceSettingHelper);

        private var view:AudienceSetting;

        private var networkDataList:Array;
        private var socketClient:SocketClient;

        private var isConnectServer:Boolean = false;

        /**
         *
         * @param document
         * @param id
         */
        public function initialized(document:Object, id:String):void
        {
            this.view = document as AudienceSetting;
            this.view.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
            this.view.filters = [FilterUtil.getDropShadowFilter()];
        }

        private function creationCompleteHandler(event:FlexEvent):void
        {
            this.view.join.addEventListener(MouseEvent.CLICK, join_clickHandler);
            this.view.back.addEventListener(MouseEvent.CLICK, back_clickHandler);

            this.checkNetwork();
        }

        /**
         * ネットワーク接続チェック
         */
        private function checkNetwork():void
        {
            // オーディエンス自身のIPAddressをネットワーク一覧から取得
            this.view.join.enabled = false;

            var networkInterfaceManager:NetworkInterfaceManager = new NetworkInterfaceManager();
            try
            {
                this.networkDataList = networkInterfaceManager.getNetworkInterfaceDataList();
            }
            catch (e:NetworkInterfaceError)
            {
                logger.warn("AudienceSettingHelper::NetworkInterfaceError");
                Alert.show("ネットワーク設定からIPv6を無効にすると正しく動作することがあります。", "IPアドレス取得エラー");

                return;
            }

            if (this.networkDataList.length > 1)
            {
                logger.info("AudienceSettingHelper::networkDataList length over 1");

                var addressList:Array = [];
                addressList.push("使用するIPを選択してください");

                for each (var networkData:NetworkInterfaceData in this.networkDataList)
                {
                    addressList.push({"label": networkData.name + "::" + networkData.address, "data": networkData});
                }

                this.view.audienceAddress.dataProvider = addressList;
                this.view.audienceAddress.addEventListener(ListEvent.CHANGE, this.audienceAddressListChangeHandler);
            }
            else if (networkDataList.length == 1)
            {
                var localInterfase:NetworkInterfaceData = NetworkInterfaceData(networkDataList[0]);
                this.view.audienceAddress.dataProvider = [{"label": localInterfase.name + "::" + localInterfase.address, "data": localInterfase}];

                this.socketClient = new SocketClient(networkDataList[0]);

                this.socketClient.addEventListener(SocketEvent.SERVER_CONNECT_SUCCESS, this.serverConnectSuccessHandler);
                this.socketClient.addEventListener(SocketEvent.SERVER_CONNECT_FAILED, this.serverConnectFailedHandler);

                try
                {
                    this.socketClient.connectByBroadcast();
                }
                catch (e:Error)
                {
                    logger.error("AudienceSettingHelper::client.connect Error catch message = {0}", e.message);

                    Alert.show("実行環境によってはこのエラーが出る場合があります。" + "スピーカーのIPアドレスを指定して接続が可能になる場合があります。", "スピーカー探索エラー");

                    this.view.join.enabled = true;
                }
            }
            else if (networkDataList.length == 0)
            {
                Alert.show("利用可能なIPアドレスが見つかりませんでした。ネットワークに接続されていることを確認してください。", "IPアドレス取得エラー");
            }
        }

        private function audienceAddressListChangeHandler(event:ListEvent):void
        {
            for each (var networkData:NetworkInterfaceData in this.networkDataList)
            {
                if (networkData == (event.target as ComboBox).selectedItem.data)
                {
                    logger.info("List =" + (event.target as ComboBox).selectedItem);

                    if (this.socketClient)
                    {
                        this.socketClient.destroy();
                        this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_SUCCESS, this.serverConnectSuccessHandler);
                        this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_FAILED, this.serverConnectFailedHandler);
                    }

                    logger.info("AudienceSettingHelper::new SocketClient address = " + networkData.address);
                    this.socketClient = new SocketClient(networkData);

                    this.socketClient.addEventListener(SocketEvent.SERVER_CONNECT_SUCCESS, this.serverConnectSuccessHandler);
                    this.socketClient.addEventListener(SocketEvent.SERVER_CONNECT_FAILED, this.serverConnectFailedHandler);

                    try
                    {
                        this.socketClient.connectByBroadcast();
                    }
                    catch (e:Error)
                    {
                        logger.error("AudienceSettingHelper::audienceAddressListChangeHandler Error catch message = " + e.message);

                        Alert.show("実行環境によってはこのエラーが出る場合があります。" + "スピーカーのIPアドレスを直指定で接続が可能になる場合があります。", "ブロードキャストエラー");

                        this.view.join.enabled = true;
                    }
                }
            }
        }

        private function serverConnectSuccessHandler(event:SocketEvent):void
        {
            logger.debug("AudienceSettingHelper::serverConnectSuccessHandler");

            ConnectInfo.socketClient = this.socketClient;

            this.isConnectServer = true;

            if (this.view.displayName.text == "")
            {
                Alert.show("スピーカーとの接続に成功しました。表示名を入力して参加ボタンを押してください。", "接続成功");

                this.view.join.enabled = true;
            }
            else
            {
                ConnectInfo.name = this.view.displayName.text;
                ConnectInfo.callBack = this.backViewFromVoteCallBack;

                this.view.join.enabled = true;
                this.view.dispatchEvent(new ViewChangeEvent(ViewChangeEvent.JOIN));
            }
            this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_SUCCESS, this.serverConnectSuccessHandler);
            this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_FAILED, this.serverConnectFailedHandler);
        }

        private function serverConnectFailedHandler(event:SocketEvent):void
        {
            logger.error("AudienceSettingHelper::serverConnectFailedHandler");

            Alert.show("スピーカーを見つけられませんでした。スピーカーのIPアドレスを指定して接続してください。", "スピーカーを見つけられませんでした");

            this.view.join.enabled = true;
        }

        /**
         * 参加ボタンクリックイベントハンドラー
         * ユーザーの入力状態により動作がことなる
         */
        private function join_clickHandler(event:MouseEvent):void
        {
            // ユーザー名が指定されており、接続確認ができているならVoteModeへ
            if (this.view.displayName.text != "" && this.isConnectServer)
            {
                ConnectInfo.name = this.view.displayName.text;
                ConnectInfo.callBack = this.backViewFromVoteCallBack;

                this.view.dispatchEvent(new ViewChangeEvent(ViewChangeEvent.JOIN));
            }
            // ユーザー名が未入力なら入力を促す
            else if (this.view.displayName.text == "" && this.isConnectServer)
            {
                Alert.show("スピーカーとの接続に成功しました。表示名を入力して参加ボタンを押してください。", "接続成功");

                this.view.join.enabled = true;

                this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_SUCCESS, this.serverConnectSuccessHandler);
                this.socketClient.removeEventListener(SocketEvent.SERVER_CONNECT_FAILED, this.serverConnectFailedHandler);
            }
            // IP指定で接続を試みる
            else
            {
                logger.info("IP指定接続 address = " + this.view.speakerAddress.text);

                if (this.view.speakerAddress.text == "")
                {
                    return;
                }
                try
                {
                    this.socketClient.connectByAddress(this.view.speakerAddress.text);
                }
                catch (e:Error)
                {
                    Alert.show("IPの書式が正しくない可能性があります。もういちど入力欄をご確認ください", "接続試行失敗");
                }
            }
        }

        /**
         * 戻るボタンクリック
         */
        private function back_clickHandler(event:Event):void
        {
            this.view.dispatchEvent(new ViewChangeEvent(ViewChangeEvent.BACK));
        }

        /**
         * 戻るボタンでVoteページから戻った際に呼び出すコールバック関数
         * @see ConnectInfo
         */
        private function backViewFromVoteCallBack():void
        {
            logger.debug("AudienceSettingHelper::backViewFromVoteCallBack");
            ConnectInfo.socketClient.destroy();

            this.checkNetwork();
            this.isConnectServer = false;
        }
    }
}

